<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
  <link rel="stylesheet" href="test.css">
  <title>Zepto Event unit tests</title>
  <script src="../vendor/evidence.js"></script>
  <script src="evidence_runner.js"></script>
  <script>
    // avoid caching
    (function(){
      function load(scripts){
        scripts.split(' ').forEach(function(script){
          document.write('<script src="../src/'+script+'.js?'+(+new Date)+'"></scr'+'ipt>')
        })
      }

      load('zepto event ie')
    })()
  </script>
</head>
<body>
  <h1>Zepto Event unit tests</h1>
  <p id="results">
    Running… see browser console for results
  </p>
  <div id="fixtures">
  </div><!-- fixtures -->

  <script>
  (function(){

    function click(el){
      var event = document.createEvent('MouseEvents')
      event.initMouseEvent('click', true, true, document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, null)
      $(el).get(0).dispatchEvent(event)
    }

    Evidence('ProxyTest', {
      testProxyFnContext: function(t){
        var a = {name: 'A', fn: function(n, o){ return this.name + n + o }},
            b = {name: 'B'}

        t.assertEqual('A13', a.fn(1, 3))
        t.assertEqual('B52', $.proxy(a.fn, b)(5, 2))
      },

      testProxyInvalidFn: function(t){
        try {
          $.proxy(null)
          t.fail("shouldn't be here")
        } catch(e) {
          t.assertEqual('TypeError', e.name)
          t.assertEqual("expected function", e.message)
        }
      },

      testProxyContextName: function(t){
        var b = {name: 'B', fn: function(n, o){ return this.name + n + o }},
            oldFn = b.fn

        t.assertEqual('B52', $.proxy(b, 'fn')(5, 2))
        t.assertIdentical(oldFn, b.fn)
      },

      testProxyUndefinedProperty: function(t){
        try {
          $.proxy({}, 'nonexistent')
          t.fail("shouldn't be here")
        } catch(e) {
          t.assertEqual('TypeError', e.name)
          t.assertEqual("expected function", e.message)
        }
      },

      testProxyInvalidProperty: function(t){
        try {
          $.proxy({num:3}, 'num')
          t.fail("shouldn't be here")
        } catch(e) {
          t.assertEqual('TypeError', e.name)
          t.assertEqual("expected function", e.message)
        }
      }
    })

    Evidence('EventTest', {
      setUp: function(){
        this.el = $('<div />').appendTo('#fixtures')
      },

      tearDown: function(){
        this.el.off().remove()
        $([document, document.body]).off()
      },

      testProxiedHandlerCanBeUnboundWithOriginal: function(t){
        var obj = {times:0, fn: function(){ this.times++ }}

        this.el.on('click', $.proxy(obj, 'fn'))
        click(this.el)
        t.assertEqual(1, obj.times)

        this.el.off('click', obj.fn)
        click(this.el)
        t.assertEqual(1, obj.times)
      },

      testOneHandlerCanBeUnboundWithOriginal: function(t){
        var count = 0, fn = function(){ count++ }

        this.el.one('click', fn)
        this.el.off('click', fn)
        click(this.el)
        t.assertEqual(0, count)
      },

      testOneDelegation: function(t){
        var context, count = 0
        $(document).one('click', 'div', function(){ context = this; count++ })

        click(this.el)
        click(this.el)
        t.assertEqual(1, count)
        t.assertIdentical(this.el.get(0), context)
      },

      testOneWithData: function(t){
        var obj = {}, gotObj, count = 0
        $(document).one('click', obj, function(e){ gotObj = e.data; count++ })

        click(this.el)
        click(this.el)
        t.assertEqual(1, count)
        t.assertIdentical(obj, gotObj)
      },

      testHandlerArity: function(t){
        var numArgs
        this.el.on('click', function(){ numArgs = arguments.length })

        click(this.el)
        t.assertEqual(1, numArgs)
      },

      testOnWithObject: function(t){
        var log = []
        this.el.on({ click: function(){ log.push('a') } }).
                on({ click: function(){ log.push('b') } }, null)

        click(this.el)
        t.assertEqual('a b', log.sort().join(' '))
      },

      testOnWithBlankData: function(t){
        var log = [], fn = function(e){ log.push(e.data) }
        this.el
          .on('click', null, fn)
          .on('click', undefined, fn)

        click(this.el)
        t.assertEqual(2, log.length)
        t.assertIdentical(null, log[0])
        t.assertIdentical(undefined, log[1])
      },

      testOffWithObject: function(t){
        var log = [],
            fn = function(){ log.push('a') },
            fn2 = function(){ log.push('b') },
            fn3 = function(){ log.push('c') }

        this.el.on('click', fn).on('click', fn2).on('click', fn3)
        click(this.el)
        t.assertEqual('a b c', log.sort().join(' '))

        this.el.off({ click: fn }).off({ click: fn2 }, null)
        click(this.el)
        t.assertEqual('a b c c', log.sort().join(' '))
      },

      testDelegateEventProperties: function(t){
        var type, target, currentTarget
        $(document).on('click', 'div', function(e){
          type = e.type
          target = e.target
          currentTarget = e.currentTarget
        })
        click($('<span>').appendTo(this.el))
        t.assertEqual('click', type)
        t.assertIdentical(this.el.find('span').get(0), target)
        t.assertIdentical(this.el.get(0), currentTarget)
      },

      testPreventDefaultWithDelegatedEvent: function(t){
        var isDefaultPrevented, span = $('<span>').appendTo(this.el)

        span.on('click', function(event){
          event.preventDefault()
        })
        $(document).on('click', 'div', function(event){
          isDefaultPrevented = event.isDefaultPrevented()
        })

        click(span)
        t.assertTrue(isDefaultPrevented, "isDefaultPrevented() value invalid for delegate proxy")
      },

      testEventsOnPlainObjects: function (t){
        var obj = {},
        	log = [],
        	fn1 = function(){ log.push('a') },
          fn2 = function(evt, value){ log.push(value)    },
        	fn3 = function(evt, value){ log.push("event2") }
        $(obj)
        	.on('event', fn1)
        	.on('event', fn2)
        	.on('event2', fn3)

        $(obj).trigger('event', 'b')
        t.assertEqual('a b', log.join(' '))

        log = []
        $(obj).trigger('event', 'c')
        t.assertEqual('a c', log.join(' '))

        log = []
        $(obj).off('event', fn1)
        $(obj).trigger('event', 'd')
        t.assertEqual('d', log.join(' '))

        log = []
        $(obj).trigger('event2');
        t.assertEqual('event2', log.join(' '));
      },

      testHandlerWithoutData: function(t){
        var gotData

        $(document).on('click', function(event){
          gotData = event.data
        })
        t.assertUndefined(gotData)

        click(this.el)
        t.assertUndefined(gotData)
      },

      testHandlerWithData: function(t){
        var data = {}, gotData, numArgs

        $(document).on('click', data, function(event){
          gotData = event.data
          numArgs = arguments.length
        })
        t.assertUndefined(gotData)

        click(this.el)
        t.assertEqual(1, numArgs)
        t.assertIdentical(data, gotData)
      },

      testDelegatedWithData: function(t){
        var data = {}, gotData, numArgs

        $(document).on('click', 'div', data, function(event){
          gotData = event.data
          numArgs = arguments.length
        })
        t.assertUndefined(gotData)

        click(this.el)
        t.assertEqual(1, numArgs)
        t.assertIdentical(data, gotData)
      },

      testTriggerWithData: function(t){
        var data = {}, gotData

        $(document).on('myevent', data, function(event){
          gotData = event.data
        })
        t.assertUndefined(gotData)

        this.el.trigger('myevent')
        t.assertIdentical(data, gotData)
      },

      testDelegateEventMethods: function(t){
        var methodName,
            eventMethods = {
              preventDefault: 'isDefaultPrevented',
              stopImmediatePropagation: 'isImmediatePropagationStopped',
              stopPropagation: 'isPropagationStopped'
            },
            eventMethodResults = {}

        $(document).on('click', 'div', function(event){
          $.each(eventMethods, function(methodName, predicate){
            if (event[methodName]) {
              event[methodName]()
              eventMethodResults[predicate] = event[predicate]()
            } else {
              console.warn("method not available: ", methodName)
            }
          })
        })

        click($('<span>').appendTo(this.el))

        $.each(eventMethodResults, function(predicate, value){
          t.assertTrue(value, predicate)
        })
      },

      testIsDefaultPreventedOnAllEvents: function(t){
        var isDefaultPrevented

        $(this.el).on('click', function(event){
          event.preventDefault()
        })
        $(document).on('click', function(event){
          isDefaultPrevented = event.isDefaultPrevented()
        })

        click(this.el)
        t.assertTrue(isDefaultPrevented)
      },

      testIsDefaultPreventedOnOriginalEventAfterDelegate: function(t){
        var isDefaultPrevented

        this.el.on('click', 'span', function(event){
          event.preventDefault()
        })
        $(document).on('click', function(event){
          isDefaultPrevented = event.isDefaultPrevented()
        })

        click($('<span>').appendTo(this.el))

        t.assertTrue(isDefaultPrevented)
      },

      testStopImmediatePropagation: function(t){
        var log = ''

        this.el
          .on('click', function(e){ log += 'A' })
          .on('click', function(e){ log += 'B'; e.stopImmediatePropagation() })
          .on('click', function(e){ log += 'C' })

        $(document).on('click', function(e){ log += 'D' })

        click(this.el)

        t.assertEqual('AB', log)
      },

      testDelegateSelectorLookupDoesNotIncludeParent: function(t){
        var fired = false

        this.el
          .addClass('offender')
          .on('click', '.offender', function(){ fired = true })

        click(this.el)

        t.assertFalse(fired)
      },

      testFalseLiteralAsCallback: function(t){
        var event = $.Event('click')

        this.el.on('click', false)

        this.el.trigger(event)
        t.assertTrue(event.isDefaultPrevented())
        t.assertTrue(event.isPropagationStopped())
      },

      testUnbindingFalseLiteral: function(t){
        var event = $.Event('click'), fired

        this.el
          .on('click', function() { fired = true })
          .on('click', false)
          .off('click', false)

        this.el.trigger(event)

        t.assertTrue(fired)
        t.assertFalse(event.isDefaultPrevented())
        t.assertFalse(event.isPropagationStopped())
      },

      testFalseLiteralAsCallbackWithDataArgument: function(t){
        var event = $.Event('click')

        this.el.on('click', null, false)

        this.el.trigger(event)
        t.assertTrue(event.isDefaultPrevented())
        t.assertTrue(event.isPropagationStopped())
      },

      testFalseLiteralAsCallbackForDelegation: function(t){
        var span = $('<span>').appendTo(this.el),
            event = $.Event('click')

        this.el.on('click', 'span', false)

        span.trigger(event)
        t.assertTrue(event.isDefaultPrevented())
        t.assertTrue(event.isPropagationStopped())
      },

      testFalseLiteralAsCallbackForDelegationWithDataArgument: function(t){
        var span = $('<span>').appendTo(this.el),
            event = $.Event('click')

        this.el.on('click', 'span', null, false)

        span.trigger(event)
        t.assertTrue(event.isDefaultPrevented())
        t.assertTrue(event.isPropagationStopped())
      }

    })
  })()
  </script>
</body>
</html>
